package com.hilinos.common.common.handler;

import com.hilinos.common.common.ReturnCode;
import com.hilinos.common.entity.RespVo;
import com.hilinos.common.util.EntityUtils;
import com.hilinos.common.util.ReturnException;
import com.hilinos.common.util.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@RestControllerAdvice
public class RequestErrorHandler {

    private static final Pattern PATTERN_PARAMETER_ERROR1 = Pattern.compile("^Optional\\ .*\\ parameter '.*'"),
            PATTERN_PARAMETER_ERROR2 = Pattern.compile("'.*'");

    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public Object error(Throwable e) {
        log.error("服务异常", e);
        return ReturnCode.FAIL.resp();
    }

    @ResponseBody
    @ExceptionHandler(value = NullPointerException.class)
    public Object error(NullPointerException e) {
        log.error("服务异常", e);
        return ReturnCode.NORMAL_SYSTEM_ERROR.resp();
    }

    @ResponseBody
    @ExceptionHandler(value = IllegalStateException.class)
    public Object error(IllegalStateException e) {

        String msg = e.getMessage();
        if (ObjectUtils.isEmpty(msg)) {
            log.warn("服务异常", e);
            return ReturnCode.NORMAL_SYSTEM_ERROR.resp();
        }

        Matcher matcher = PATTERN_PARAMETER_ERROR1.matcher(msg);
        while (matcher.find()) {
            String i = matcher.group(0);
            matcher = PATTERN_PARAMETER_ERROR2.matcher(i);
            while (matcher.find()) {
                String paramName = matcher.group(0).replace("'", "");
                return ReturnCode.NORMAL_PARAM_LOST_ERROR.respMsg(paramName + "不能为空");
            }
        }

        return ReturnCode.NORMAL_SYSTEM_ERROR.resp();
    }

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public Object error(MethodArgumentTypeMismatchException e) {
        ServletUtils.getResponse().setHeader("error", e.getLocalizedMessage());
        log.error("参数转换失败，方法：" + Objects.requireNonNull(e.getParameter().getMethod()).getName() + ",参数：" +
                e.getName() + "，信息：" + e.getLocalizedMessage());
        return ReturnCode.NORMAL_PARAM_TYPE_ERROR.respMsg("参数类型错误,参数：" + e.getName());
    }

    @ResponseBody
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public Object error(HttpRequestMethodNotSupportedException e) {
        log.error("不支持({})请求方式", e.getMethod());
        return ReturnCode.NORMAL_REQUEST_NOT_SUPPORTED.respMsg("不支持" + e.getMethod() + "请求方式");
    }

    @ResponseBody
    @ExceptionHandler(value = ReturnException.class)
    public Object error(ReturnException e) {

        if (!ObjectUtils.isEmpty(e.getMessageStr())) {
            RespVo<Object> respVo = ReturnCode.FAIL.resp();
            respVo.setMsg(e.getMessageStr());
            log.error("服务异常:{}", e.getMessageStr());
            return respVo;
        } else if (!ObjectUtils.isEmpty(e.getMsg())) {
            log.error("服务异常:{}", EntityUtils.toJsonString(e.getMsg()));
            return e.getMsg();
        }
        return ReturnCode.FAIL.resp();
    }

    @ResponseBody
    @ExceptionHandler(value = {BindException.class})
    public Object error(BindException e) {
        List<ObjectError> errors = e.getAllErrors();
        List<ObjectError> tmpErrors = new ArrayList<>(errors);
        tmpErrors.sort(Comparator.comparingInt(ObjectError::hashCode));
        log.error("参数错误 {}:{}", Objects.requireNonNull(tmpErrors.get(0).getCodes())[1],
                tmpErrors.get(0).getDefaultMessage());
        return ReturnCode.NORMAL_PARAM_TYPE_ERROR.respMsg(tmpErrors.get(0).getDefaultMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object error(MethodArgumentNotValidException e) {
        return error(new BindException(e.getBindingResult()));
    }

    @ResponseBody
    @ExceptionHandler(value = HttpMediaTypeNotAcceptableException.class)
    public Object error(HttpMediaTypeNotAcceptableException e) {
        return ReturnCode.FAIL.resp();
    }

    @ResponseBody
    @ExceptionHandler(value = ServletRequestBindingException.class)
    public Object error(ServletRequestBindingException e) {
        log.error("参数缺失", e);
        return ReturnCode.NORMAL_PARAM_LOST_ERROR.respMsg(e.getLocalizedMessage());
    }

}
